#ifndef _K_POINTER_
#define _K_POINTER_

#include "KInterlock.h"

namespace krt
{
	template<class type>
	class auto_ptr
	{
	public:
		typedef type value_type;
		typedef type *pointer;
		typedef const type *const_pointer;
		typedef type &reference;
		typedef const type &const_reference;

		inline auto_ptr() 
		{
			m_ptr = new value_type;
		}

		inline auto_ptr(value_type *ptr): m_ptr(ptr){}

		inline ~auto_ptr()
		{
			if (m_ptr)
				delete m_ptr;
		}

		inline value_type* operator->()
		{
			return m_ptr;
		}

		inline value_type& operator*()
		{
			return (*m_ptr);
		}

		inline value_type* GetPointer()
		{
			return m_ptr;
		}

	private:
		value_type *m_ptr;
		auto_ptr(const auto_ptr& other);
		auto_ptr& operator=(const auto_ptr& other);
	};

	template<class type>
	class shared_ptr
	{
	public:
		typedef type value_type;
		typedef type *pointer;
		typedef const type *const_pointer;
		typedef type &reference;
		typedef const type &const_reference;

		inline shared_ptr(): m_ptr(NULL), m_nRef(NULL) 
		{
			this->SetPointer(new value_type);
		}

		inline shared_ptr(value_type *ptr): m_ptr(NULL), m_nRef(NULL)
		{
			this->SetPointer(ptr);
		}

		inline shared_ptr(shared_ptr& src): m_ptr(NULL), m_nRef(NULL)
		{
			this->assign(src);
		}

		inline ~shared_ptr()
		{
			this->release();
		}

		shared_ptr& operator=(const shared_ptr& other)
		{
			this->assign(src);
		}

		inline value_type* operator->()
		{
			return this->m_ptr;
		}

		inline value_type& operator*()
		{
			return (*this->m_ptr);
		}

		inline value_type* GetPointer()
		{
			return m_ptr;
		}

	private:
		value_type *m_ptr;
		volatile long *m_nRef;

		inline void SetPointer(value_type *ptr)
		{
			this->release();
			this->m_nRef = new long;
			*(this->m_nRef) = 1;
			this->m_ptr = ptr;
		}

		inline long AddRef()
		{
			return LockInc(m_nRef);
		}

		inline long release()
		{
			if (!m_nRef)
				return 0;

			long result = LockDec(m_nRef);

			if (!result)
			{
				if (m_ptr)
				{
					delete m_ptr;
					m_ptr = NULL;
				}

				if (m_nRef)
				{
					delete m_nRef;
					m_nRef = NULL;
				}			
			}

			return result;
		}

		inline void assign(shared_ptr& src) 
		{
			this->release();
			src.AddRef();
			this->m_nRef = src.m_nRef;
			this->m_ptr = src.m_ptr;
		}

	};
}
#endif	//_K_POINTER_	